home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / cw_field.pro < prev    next >
Text File  |  1997-07-08  |  16KB  |  566 lines

  1. ; $Id: cw_field.pro,v 1.12 1997/01/15 03:11:50 ali Exp $
  2. ;
  3. ; Copyright (c) 1992-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    CW_FIELD
  8. ;
  9. ; PURPOSE:
  10. ;    This widget cluster function manages a data entry field widget.
  11. ;    The field consists of a label and a text widget.  CW_FIELD's can
  12. ;    be string fields, integer fields or floating-point fields.  The
  13. ;    default is an editable string field.
  14. ;
  15. ; CATEGORY:
  16. ;    Widget Clusters.
  17. ;
  18. ; CALLING SEQUENCE:
  19. ;    Result = CW_FIELD(Parent)
  20. ;
  21. ; INPUTS:
  22. ;    Parent:    The widget ID of the widget to be the field's parent.
  23. ;
  24. ; KEYWORD PARAMETERS:
  25. ;    TITLE:    A string containing the text to be used as the label for the
  26. ;        field.  The default is "Input Field:".
  27. ;
  28. ;    VALUE:    The initial value in the text widget.  This value is
  29. ;        automatically converted to the type set by the STRING,
  30. ;        INTEGER, and FLOATING keywords described below.
  31. ;
  32. ;    UVALUE:    A user value to assign to the field cluster.  This value
  33. ;        can be of any type.
  34. ;
  35. ;    FRAME:    The width, in pixels, of a frame to be drawn around the
  36. ;        entire field cluster.  The default is no frame.
  37. ;
  38. ;RETURN_EVENTS:    Set this keyword to make cluster return an event when a
  39. ;        <CR> is pressed in a text field.  The default is
  40. ;        not to return events.  Note that the value of the text field
  41. ;        is always returned when the WIDGET_CONTROL, field, GET_VALUE=X
  42. ;        command is used.
  43. ;
  44. ;   ALL_EVENTS: Like RETURN_EVENTS but return an event whenever the
  45. ;        contents of a text field have changed.
  46. ;
  47. ;    COLUMN:    Set this keyword to center the label above the text field.
  48. ;        The default is to position the label to the left of the text
  49. ;        field.
  50. ;
  51. ;    ROW:    Set this keyword to position the label to the left of the text
  52. ;        field.  This is the default.
  53. ;
  54. ;    XSIZE:    An explicit horizontal size (in characters) for the text input
  55. ;        area.  The default is to let the window manager size the
  56. ;        widget.  Using the XSIZE keyword is not recommended.
  57. ;
  58. ;    YSIZE:    An explicit vertical size (in lines) for the text input
  59. ;        area.  The default is 1.
  60. ;
  61. ;    STRING:    Set this keyword to have the field accept only string values.
  62. ;        Numbers entered in the field are converted to their string
  63. ;        equivalents.  This is the default.
  64. ;
  65. ;     FLOATING:    Set this keyword to have the field accept only floating-point
  66. ;        values.  Any number or string entered is converted to its
  67. ;        floating-point equivalent.
  68. ;
  69. ;      INTEGER:    Set this keyword to have the field accept only integer values.
  70. ;        Any number or string entered is converted to its integer
  71. ;        equivalent (using FIX).  For example, if 12.5 is entered in
  72. ;        this type of field, it is converted to 12.
  73. ;
  74. ;    LONG:    Set this keyword to have the field accept only long integer
  75. ;        values.  Any number or string entered is converted to its
  76. ;        long integer equivalent (using LONG).
  77. ;
  78. ;    FONT:    A string containing the name of the X Windows font to use
  79. ;        for the TITLE of the field.
  80. ;
  81. ;    FIELDFONT:    A string containing the name of the X Windows font to use
  82. ;        for the TEXT part of the field.
  83. ;
  84. ;    NOEDIT:    Normally, the value in the text field can be edited.  Set this
  85. ;        keyword to make the field non-editable.
  86. ;
  87. ; OUTPUTS:
  88. ;    This function returns the widget ID of the newly-created cluster.
  89. ;
  90. ; COMMON BLOCKS:
  91. ;    None.
  92. ;
  93. ; PROCEDURE:
  94. ;    Create the widgets, set up the appropriate event handlers, and return
  95. ;    the widget ID of the newly-created cluster.
  96. ;
  97. ; EXAMPLE:
  98. ;    The code below creates a main base with a field cluster attached
  99. ;    to it.  The cluster accepts string input, has the title "Name:", and
  100. ;    has a frame around it:
  101. ;
  102. ;        base = WIDGET_BASE()
  103. ;        field = CW_FIELD(base, TITLE="Name:", /FRAME)
  104. ;        WIDGET_CONTROL, base, /REALIZE
  105. ;
  106. ; MODIFICATION HISTORY:
  107. ;     Written by:    Keith R. Crosley   June 1992
  108. ;            KRC, January 1993 -- Added support for LONG
  109. ;                         integers.
  110. ;                AB, 7 April 1993, Removed state caching.
  111. ;            JWG, August 1993, Completely rewritten to make
  112. ;                use of improved TEXT widget functionality
  113. ;            ACY, 25 March, 1994, fix usage of FRAME keyword
  114. ;                       KDB, May 1994, Initial value =0 would result
  115. ;                                      in a null text field. Fixed
  116. ;                                      keyword check.
  117. ;
  118. ;-
  119.  
  120. ;
  121. ;  Check and return the portion of a string that
  122. ;    is a valid floating point number.
  123. ;
  124. FUNCTION CW_FIELD_VALIDATE, Value
  125.     ;    Look for invalid mantissa
  126.  
  127.     IF Value EQ '' THEN RETURN, ''
  128.  
  129.     Chars    = [ BYTE(Value), 0b ]
  130.     Curr    = 0
  131.     NeedDecimal    = 1
  132.  
  133.     ;    Valid #s
  134.     ;    [+-]<number>[exponent]
  135.     ;    number ::= [0-9]+[.[0-9]*] or .[0-9]+
  136.     ;    exponent ::= {eEdD}[+-][0-9]+
  137.  
  138.     ;    Signed value?
  139.     IF Chars[Curr] EQ 43b OR Chars[Curr] EQ 45b THEN Curr = Curr + 1
  140.  
  141.     ;    Look for digits before the decimal point
  142.     IF Chars[Curr] GE 48b AND Chars[Curr] LE 57b THEN BEGIN
  143.     NeedDecimal    = 0
  144.  
  145.     ;    while(isdigit(*p))++p;
  146.     WHILE Chars[Curr] GE 48b AND Chars[Curr] LE 57b DO Curr = Curr + 1
  147.     ENDIF
  148.  
  149.     ;    Must have .[0-9]+
  150.  
  151.     IF NeedDecimal THEN BEGIN
  152.     IF Chars[Curr] NE 46b THEN RETURN,''    ; invalid #
  153.     Curr    = Curr + 1
  154.     IF Chars[Curr] LT 48b OR Chars[Curr] GT 57b THEN RETURN,''
  155.  
  156.     ;    while(isdigit(*p))++p;
  157.     WHILE Chars[Curr] GE 48b AND Chars[Curr] LE 57b DO Curr = Curr + 1
  158.     ENDIF ELSE BEGIN
  159.  
  160.     ;    Might have .[0-9]*
  161.  
  162.     IF Chars[Curr] EQ 46b THEN BEGIN
  163.         Curr    = Curr + 1
  164.         ;    while(isdigit(*p))++p;
  165.         WHILE Chars[Curr] GE 48b AND Chars[Curr] LE 57b DO Curr = Curr + 1
  166.     ENDIF
  167.     ENDELSE
  168.  
  169.     ;    Exponent?
  170.     Dummy    = WHERE(Chars[Curr] EQ BYTE("dDeE"), Count)
  171.     IF Count THEN BEGIN
  172.     ; Save exponent position in case the exponent is invalid
  173.     ; and only mantissa is valid number.
  174.     SaveCurr    = Curr - 1
  175.  
  176.     Curr        = Curr + 1    ; skip 'e'
  177.     ;    Signed exponent?
  178.     IF Chars[Curr] EQ 43b OR Chars[Curr] EQ 45b THEN Curr = Curr + 1
  179.  
  180.     ;    At least one digit after 'e' or exponent is malformed
  181.     IF Chars[Curr] LT 48b OR Chars[Curr] GT 57b THEN BEGIN
  182.         Curr    = SaveCurr    ; Revert -- invalid exponent
  183.     ENDIF ELSE BEGIN
  184.     ;    find end of exponent digits
  185.         WHILE Chars[Curr] GE 48b AND Chars[Curr] LE 57b DO Curr = Curr + 1
  186.     ENDELSE
  187.     ENDIF
  188.  
  189.     RETURN,STRING(Chars[0:Curr])    ; Chars from 0-Curr are valid
  190. END
  191.  
  192.  
  193. FUNCTION CW_FIELD_VALUE, Value, Type
  194.  
  195.     IF Type EQ 0 THEN RETURN, Value
  196.  
  197.     NValue    = CW_FIELD_VALIDATE(Value[0])
  198.  
  199.     CASE Type OF
  200.     1:    RETURN, FLOAT(NValue)
  201.     2:    RETURN, FIX(NValue)
  202.     3:    RETURN, LONG(NValue)
  203.     ENDCASE
  204. END
  205.  
  206. ;
  207. ;    Procedure to set the value of a CW_FIELD
  208. ;
  209. PRO CW_FIELD_SET, Base, Value
  210.  
  211.     sValue    = Value        ; Prevent alteration from reaching back to caller
  212.  
  213.     Sz    = SIZE(sValue)
  214.     IF Sz[0] NE 7 THEN sValue = STRTRIM(Value,2)
  215.  
  216.     Child    = WIDGET_INFO(Base, /CHILD)
  217.     WIDGET_CONTROL, Child, GET_UVALUE=State, /NO_COPY
  218.     WIDGET_CONTROL, State.TextId, $
  219.         SET_VALUE=STRTRIM(CW_FIELD_VALUE(sValue, State.Type),2)
  220.     WIDGET_CONTROL, Child, SET_UVALUE=State, /NO_COPY
  221. END
  222.  
  223. ;
  224. ;    Function to get the value of a CW_FIELD
  225. ;
  226. FUNCTION CW_FIELD_GET, Base
  227.  
  228.     Child    = WIDGET_INFO(Base, /CHILD)
  229.     WIDGET_CONTROL, Child, GET_UVALUE=State, /NO_COPY
  230.     WIDGET_CONTROL, State.TextId, GET_VALUE=Value
  231.  
  232.     Ret    = CW_FIELD_VALUE(Value, State.Type)
  233.  
  234.     WIDGET_CONTROL, Child, SET_UVALUE=State, /NO_COPY
  235.     RETURN, Ret
  236. END
  237.  
  238. ;    Ascii assumptions
  239. ;
  240. ;    + - .    = 43,45,46
  241. ;    0-9    = 48-57
  242. ;    DEde    = 68,69,100,101
  243. ;
  244.  
  245. ;
  246. ;    Examine an input stream of characters.
  247. ;    Alter the field contents to reflect this.
  248. ;    If any character inserted in a single operation is invalid,
  249. ;        ignore the entire operation.
  250. ;    Consider that field may contain a (known) invalid state
  251. ;
  252. PRO CW_FIELD_INT, Ch, State, Event, Altered
  253.  
  254.     Altered    = 0        ; nothing so far
  255.     Nil        = 0        ; field has contents
  256.     Minus    = 0        ; field is not just a '-'
  257.     Negate    = 0        ; new text has no '-'s in it
  258.     TextId    = State.TextId
  259.  
  260.     ; Special Cases:
  261.     ;    We don't actually care where in the input string a
  262.     ;    '-' is.  If there is an odd number of them, we
  263.     ;    negate the value (see below)
  264.     ;
  265.     ;    Current String        Char        Result
  266.     ;    Nil            '-'        '-'
  267.     ;    -            '-'        Nil
  268.     ;    <any number>        '-'        -<number>
  269.  
  270.     WIDGET_CONTROL, TextId, GET_VALUE=Value
  271.     Value    = Value[0]
  272.  
  273.     IF Value EQ '' THEN Nil = 1        ; Value is nil string
  274.     IF Value EQ '-' THEN Minus = 1    ; Value is an invalid number
  275.  
  276.  
  277.     ;    <CR> 
  278.     IF Ch EQ 10b THEN BEGIN
  279.     Altered    = 2
  280.     RETURN
  281.     ENDIF
  282.  
  283.     IF Ch EQ 45b THEN Negate = 1 $
  284.     ELSE IF Ch GE 48b AND Ch LE 57b THEN BEGIN
  285.     Nil = 0 & Minus = 0
  286.     ENDIF ELSE RETURN    ; ![0-9]
  287.  
  288.     ;    Add new character (if any)
  289.  
  290.     Selection    = WIDGET_INFO(TextId, /TEXT_SELECT)
  291.     TIP        = Selection[0]+1-Negate    ; Text Insertion Point
  292.  
  293.     IF Negate EQ 0 THEN BEGIN
  294.     WIDGET_CONTROL, TextId, SET_VALUE=STRING(Ch), /USE_TEXT_SELECT
  295.     Altered    = 1
  296.     ENDIF
  297.  
  298.     IF Negate THEN BEGIN
  299.     IF Nil THEN BEGIN
  300.         WIDGET_CONTROL, TextId, SET_VALUE='-'
  301.         TIP    = 1
  302.     ENDIF ELSE IF Minus THEN BEGIN
  303.         WIDGET_CONTROL, TextId, SET_VALUE=''
  304.     ENDIF ELSE BEGIN
  305.         ;    We actually have a number to negate
  306.  
  307.         WIDGET_CONTROL, TextId, GET_VALUE=Value
  308.         IValue    = LONG(Value)
  309.         TIP        = TIP + (IValue GT 0) - (IValue LT 0)
  310.         WIDGET_CONTROL, TextId, SET_VALUE=STRTRIM(-IValue,2)
  311.     ENDELSE
  312.     Altered    = 1
  313.     ENDIF
  314.  
  315.     ; Set selection point
  316.     IF Altered THEN WIDGET_CONTROL, TextId, SET_TEXT_SELECT=[TIP,0]
  317. END
  318.  
  319.  
  320. FUNCTION CW_FIELD_EXPONENT, Value, Idx
  321.  
  322.     BValue    = BYTE(Value)
  323.  
  324.     Idx    = WHERE(BValue EQ 68b, Count)
  325.     IF Count EQ 1 THEN RETURN, 1
  326.     Idx    = WHERE(BValue EQ 69b, Count)
  327.     IF Count EQ 1 THEN RETURN, 1
  328.     Idx    = WHERE(BValue EQ 100b, Count)
  329.     IF Count EQ 1 THEN RETURN, 1
  330.     Idx    = WHERE(BValue EQ 101b, Count)
  331.     IF Count EQ 1 THEN RETURN, 1
  332.     RETURN, 0
  333. END
  334.  
  335. ;
  336. ;    Floating point number are even more complicated.
  337. ;    There are more invalid states available.
  338. ;    Currently, we are more lax.
  339. ;
  340. PRO CW_FIELD_FLOAT, Ch, State, Event, Altered
  341.  
  342.     TextId    = State.TextId
  343.     WIDGET_CONTROL, TextId, GET_VALUE=Value
  344.     Value    = Value[0]
  345.  
  346.     IF Ch EQ 10b THEN BEGIN
  347.     Value    = CW_FIELD_VALIDATE(Value)
  348.     WIDGET_CONTROL, TextId, SET_VALUE=Value
  349.     WIDGET_CONTROL, TextId, SET_TEXT_SELECT=[Strlen(Value),0]
  350.     Altered    = 2
  351.     RETURN
  352.     ENDIF
  353.  
  354.     ;    Unfortunately, we have a lot of invalid states
  355.     ;    possible that aren't a problem.
  356.     ;    We make sure of just a minimum number of
  357.     ;    things:
  358.     ;    One EeDd per field.
  359.     ;    One decimal point, before the exponent
  360.     ;    - sign must be 1st char or follow the exponent.
  361.  
  362.     Selection    = WIDGET_INFO(TextId, /TEXT_SELECT)
  363.  
  364.     IF Ch GE 48b AND Ch LE 57b THEN BEGIN
  365.     WIDGET_CONTROL, TextId, SET_VALUE=STRING(Ch), /USE_TEXT_SELECT
  366.     ENDIF ELSE BEGIN
  367.     CASE Ch OF
  368.  
  369.     46b:    BEGIN
  370.         ;    Ignore it if there is one already
  371.         ;    New decimal point must precede exponent
  372.  
  373.         Idx    = WHERE(BYTE(Value) EQ 46b, Count)
  374.         IF Count EQ 1 THEN RETURN
  375.         IF CW_FIELD_EXPONENT( Value, Idx ) THEN BEGIN
  376.         IF Idx[0] LT Selection[0] THEN RETURN
  377.         ENDIF
  378.         WIDGET_CONTROL, TextId, SET_VALUE=STRING(Ch), /USE_TEXT_SELECT
  379.     END
  380.     43b:    BEGIN    ; + must follow exponent
  381.         IF CW_FIELD_EXPONENT( Value, Idx ) THEN BEGIN
  382.         IF Idx[0]+1 EQ Selection[0] THEN BEGIN
  383.             WIDGET_CONTROL, TextId, SET_VALUE='+', /USE_TEXT_SELECT
  384.         ENDIF ELSE RETURN
  385.         ENDIF ELSE RETURN
  386.     END
  387.     45b:    BEGIN
  388.         HaveExp    = CW_FIELD_EXPONENT( Value, Idx )
  389.         IF  (HaveExp AND Idx[0]+1 EQ Selection[0]) OR $
  390.         (Selection[0] EQ 0 AND STRMID(Value,0,1) NE "-") THEN BEGIN
  391.         WIDGET_CONTROL, TextId, SET_VALUE='-', /USE_TEXT_SELECT
  392.         ENDIF ELSE RETURN
  393.     END
  394.  
  395.     68b:    GOTO, Exponent
  396.     69b:    GOTO, Exponent
  397.     100b:    GOTO, Exponent
  398.     101b:    BEGIN
  399.     Exponent:
  400.  
  401.     ;    Replace if one exists. Otherwise allow it anywhere
  402.     ;    AFTER the decimal point
  403.         IF CW_FIELD_EXPONENT( Value, Idx ) THEN BEGIN
  404.         Selection    = [ Idx, 1 ]
  405.         WIDGET_CONTROL, TextId, SET_TEXT_SELECT=Selection
  406.         ENDIF ELSE BEGIN
  407.         Idx    = WHERE(BYTE(Value) EQ 46b, Count)
  408.         IF Count EQ 1 THEN BEGIN
  409.             IF Selection[0] LE Idx[0] THEN RETURN
  410.         ENDIF
  411.         ENDELSE
  412.         WIDGET_CONTROL, TextId, SET_VALUE=STRING(Ch), /USE_TEXT_SELECT
  413.     END
  414.  
  415.     ELSE:    RETURN    ; Bad
  416.     ENDCASE
  417.     ENDELSE
  418.  
  419.  
  420.  
  421.     Altered    = 1
  422.     WIDGET_CONTROL, TextId, SET_TEXT_SELECT=[Selection[0]+1,0]
  423. END
  424.  
  425. FUNCTION CW_FIELD_EVENT, Event
  426.  
  427.     StateHolder    = WIDGET_INFO(Event.Handler, /CHILD)
  428.     WIDGET_CONTROL, StateHolder, GET_UVALUE=State, /NO_COPY
  429.  
  430.     ;    At this point, we need to look at what kind of field
  431.     ;    we have:
  432.  
  433.     Altered    = 0
  434.  
  435.     ;    If the user has types <CR> then update field
  436.  
  437.     IF State.Type NE 0 THEN BEGIN        ; Not a String?
  438.  
  439.     IF Event.Type LE 1 THEN BEGIN        ; Insert Characters?
  440.  
  441.         IF State.Type EQ 1 THEN Procedure='CW_FIELD_FLOAT' $
  442.         ELSE Procedure='CW_FIELD_INT'
  443.  
  444.         Altered    = 0
  445.         IF Event.Type EQ 0 THEN BEGIN
  446.         CALL_PROCEDURE, Procedure, Event.Ch, State, Event, Altered
  447.         ENDIF ELSE BEGIN
  448.         Chars    = BYTE(Event.Str)
  449.         FOR I=0,N_ELEMENTS(Chars)-1 DO $
  450.             CALL_PROCEDURE, Procedure, Chars[I], State, Event, Altered
  451.         ENDELSE
  452.  
  453.     ENDIF ELSE IF Event.Type EQ 2 THEN BEGIN    ; Delete Text
  454.  
  455.         IF Event.Length GT 0 THEN BEGIN ; Bug in widget
  456.         WIDGET_CONTROL, State.TextId, $
  457.             SET_TEXT_SELECT=[Event.Offset,Event.Length]
  458.         WIDGET_CONTROL, State.TextId, SET_VALUE='', /USE_TEXT_SELECT
  459.  
  460.         ;    See if user wants an update
  461.             Altered = 1
  462.         ENDIF
  463.  
  464.     ENDIF
  465.     ENDIF ELSE BEGIN
  466.     ;    All delete/add char events effect the contents of
  467.     ;    a string. <CR> is considered special.
  468.     IF Event.Type GE 0 AND Event.Type LE 2 THEN Altered    = 1
  469.     IF Event.Type EQ 0 THEN $
  470.        Altered    = 1 + (Event.Ch EQ 10b)
  471.     ENDELSE
  472.  
  473.  
  474.     Ret    = 0
  475.  
  476.     ;    If the entry has been modified or <CR> was hit
  477.     ;    And the user is interested in all event or
  478.     ;    Just <CR> AND <CR> was the cause of update then
  479.     ;    send it
  480.     IF State.Update NE 0 AND $
  481.        Altered GE State.Update THEN BEGIN
  482.  
  483.     WIDGET_CONTROL, State.TextId, GET_VALUE=Value
  484.     RValue    = CW_FIELD_VALUE(Value, State.Type)
  485.  
  486.     Ret    = {            $
  487.         ID: Event.Handler,    $
  488.         TOP: Event.Top,        $
  489.         HANDLER: 0L,        $
  490.         VALUE: RValue,        $
  491.         TYPE: State.Type,    $
  492.         UPDATE: Altered - 1    $    ; 0=any,1=CR
  493.     }
  494.     ENDIF
  495.  
  496.     ;    Restore our state structure
  497.     WIDGET_CONTROL, StateHolder, SET_UVALUE=State, /NO_COPY
  498.     RETURN, Ret
  499. END
  500.  
  501.  
  502. FUNCTION CW_FIELD, Parent, COLUMN=Column, ROW=Row, $
  503.     FLOATING=Float, INTEGER=Int, LONG=Long, STRING=String, $
  504.     FONT=LabelFont, FRAME=Frame, TITLE=Title, UVALUE=UValue, VALUE=Value, $
  505.     RETURN_EVENTS=ReturnEvents, ALL_EVENTS=AllUpdates, $
  506.     FIELDFONT=FieldFont, NOEDIT=NoEdit, TEXT_FRAME=TextFrame, $
  507.     XSIZE=XSize, YSIZE=YSize
  508. ;    FLOOR=vmin, CEILING=vmax
  509.  
  510.     ;    Examine our keyword list and set default values
  511.     ;    for keywords that are not explicitly set.
  512.  
  513.     Column        = KEYWORD_SET(Column)
  514.     Row            = 1 - Column
  515.     AllEvents        = 1 - KEYWORD_SET(NoEdit)
  516.  
  517.     ; Enum Update { None, All, CRonly }
  518.     Update        = 0
  519.     IF KEYWORD_SET(AllUpdates) THEN Update    = 1
  520.     IF KEYWORD_SET(ReturnEvents) THEN Update    = 2
  521.  
  522.     IF KEYWORD_SET(FieldFont) EQ 0 THEN FieldFont=''
  523.     IF KEYWORD_SET(Frame) EQ 0 THEN Frame=0
  524.     IF KEYWORD_SET(LabelFont) EQ 0 THEN LabelFont=''
  525.     IF KEYWORD_SET(Title) EQ 0 THEN Title="Input Field:"
  526.     IF N_Elements(value) EQ 0 THEN value=''
  527.     IF KEYWORD_SET(UValue) EQ 0 THEN UValue=0
  528.     IF KEYWORD_SET(XSize) EQ 0 THEN XSize=0
  529.     IF KEYWORD_SET(YSize) EQ 0 THEN YSize=1
  530.  
  531.                 Type    = 0    ; string is default
  532.     IF KEYWORD_SET(Float) THEN     Type    = 1
  533.     IF KEYWORD_SET(Int) THEN    Type    = 2
  534.     IF KEYWORD_SET(Long) THEN    Type    = 3
  535.  
  536.     ;    Don't allow multiline non string widgets
  537.     IF KEYWORD_SET(YSize) EQ 0 OR Type NE 0 THEN YSize=1
  538.     TextFrame    = KEYWORD_SET( TextFrame )
  539.  
  540.     ;    Build Widget
  541.  
  542.     Base    = WIDGET_BASE(Parent, ROW=Row, COLUMN=Column, UVALUE=UValue, $
  543.             EVENT_FUNC='CW_FIELD_EVENT', $
  544.             PRO_SET_VALUE='CW_FIELD_SET', $
  545.             FUNC_GET_VALUE='CW_FIELD_GET', $
  546.             FRAME=Frame )
  547.     Label    = WIDGET_LABEL(Base, VALUE=Title, FONT=LabelFont)
  548.     Text    = WIDGET_TEXT(Base, VALUE=STRTRIM(Value,2), $
  549.             XSIZE=XSize, YSIZE=YSize, FONT=FieldFont, $
  550.             ALL_EVENTS=AllEvents, $
  551.             EDITABLE=(AllEvents AND TYPE EQ 0), $
  552.             FRAME=TextFrame )
  553.  
  554.             ; NO_ECHO=(AllEvents AND (TYPE NE 0)))
  555.  
  556.     ; Save our internal state in the first child widget
  557.     State    = {        $
  558.     TextId:Text,        $
  559.     Title:Title,        $
  560.     Update:Update,        $
  561.     Type:Type        $
  562.     }
  563.     WIDGET_CONTROL, WIDGET_INFO(Base, /CHILD), SET_UVALUE=State, /NO_COPY
  564.     RETURN, Base
  565. END
  566.